page.tsx 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import { getPageImage, getPageMarkdownUrl, source } from '@/lib/source';
  2. import {
  3. DocsBody,
  4. DocsDescription,
  5. DocsPage,
  6. DocsTitle,
  7. MarkdownCopyButton,
  8. ViewOptionsPopover,
  9. } from 'fumadocs-ui/layouts/docs/page';
  10. import { notFound } from 'next/navigation';
  11. import { getMDXComponents } from '@/components/mdx';
  12. import { OpenAPIPage as BaseOpenAPIPage } from '@/components/openapi-page';
  13. import { openapi } from '@/lib/openapi';
  14. import type { Metadata } from 'next';
  15. import type { ComponentProps } from 'react';
  16. import { createRelativeLink } from 'fumadocs-ui/mdx';
  17. import { gitConfig } from '@/lib/shared';
  18. export default async function Page(props: PageProps<'/[lang]/docs/[[...slug]]'>) {
  19. const { lang, slug } = await props.params;
  20. const page = source.getPage(slug, lang);
  21. if (!page) notFound();
  22. const MDX = page.data.body;
  23. const markdownUrl = getPageMarkdownUrl(page).url;
  24. const editUrl = `https://github.com/${gitConfig.user}/${gitConfig.repo}/blob/${gitConfig.branch}/${gitConfig.docsDir}/${page.path}`;
  25. // Generated API reference pages carry `_openapi` metadata. Preload the spec
  26. // on the server (highlighting included) so the client OpenAPIPage doesn't have
  27. // to load it at render time.
  28. const isOpenAPI = Boolean((page.data as { _openapi?: unknown })._openapi);
  29. const extraComponents: Record<string, unknown> = {};
  30. if (isOpenAPI) {
  31. const preloaded = await openapi.preloadOpenAPIPage(page);
  32. function PreloadedOpenAPIPage(p: ComponentProps<typeof BaseOpenAPIPage>) {
  33. return <BaseOpenAPIPage {...p} {...preloaded} />;
  34. }
  35. extraComponents.OpenAPIPage = PreloadedOpenAPIPage;
  36. }
  37. return (
  38. <DocsPage toc={page.data.toc} full={page.data.full}>
  39. <DocsTitle>{page.data.title}</DocsTitle>
  40. <DocsDescription className="mb-0">{page.data.description}</DocsDescription>
  41. <div className="flex flex-row items-center gap-2 border-b pb-6">
  42. <MarkdownCopyButton markdownUrl={markdownUrl} />
  43. <ViewOptionsPopover markdownUrl={markdownUrl} githubUrl={editUrl} />
  44. </div>
  45. <DocsBody>
  46. <MDX
  47. components={getMDXComponents({
  48. // allows linking to other pages with relative file paths
  49. a: createRelativeLink(source, page),
  50. ...extraComponents,
  51. })}
  52. />
  53. </DocsBody>
  54. </DocsPage>
  55. );
  56. }
  57. export async function generateStaticParams() {
  58. return source.generateParams();
  59. }
  60. export async function generateMetadata(
  61. props: PageProps<'/[lang]/docs/[[...slug]]'>,
  62. ): Promise<Metadata> {
  63. const { lang, slug } = await props.params;
  64. const page = source.getPage(slug, lang);
  65. if (!page) notFound();
  66. return {
  67. title: page.data.title,
  68. description: page.data.description,
  69. openGraph: {
  70. images: getPageImage(page).url,
  71. },
  72. };
  73. }